package com.vstartek.dm.mongo.dao.impl;

import java.beans.Transient;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.vstartek.dm.util.PageParam;

public abstract class BaseDao<T> {

	@Autowired
	MongoTemplate mongoTemplate;

	public abstract Class<T> EntityClass();

	public T findById(Object id) {
		return mongoTemplate.findById(id, this.EntityClass());
	}
	
	public T findById(Object id, String tableName) {
		return mongoTemplate.findById(id, this.EntityClass(),tableName);
	}

	public List<T> findByList(T t, int first, int max) {
		Query query = new Query();
		query.skip(first);
		query.limit(max);
		return mongoTemplate.find(query, this.EntityClass());
	}

	public List<T> findByList(T t, int first, int max, String tableName) {
		Query query = new Query();
		query.skip(first);
		query.limit(max);
		return mongoTemplate.find(query, this.EntityClass(), tableName);
	}

	public Long totalnum(T t) {
		Query query = new Query();
		return mongoTemplate.count(query, this.EntityClass());
	}

	public Long totalnum(T t, String tableName) {
		Query query = new Query();
		return mongoTemplate.count(query, tableName);
	}
	
	public List<T> findByList(Query query) {
		return mongoTemplate.find(query, this.EntityClass());
	}

	public Long totalnum(Query query) {
		return mongoTemplate.count(query, this.EntityClass());
	}
	public List<T> findByList(Query query,PageParam pageParam){
		query.skip(pageParam.getFirst());
		query.limit(pageParam.getRows());
		String str = pageParam.getOrder().trim().toLowerCase();
		if(str!=null&&str.equals("asc")){
			query.with(new Sort(Direction.ASC,pageParam.getSort()));
		}
		if(str!=null&&str.equals("desc")){
			query.with(new Sort(Direction.DESC,pageParam.getSort()));
		}
		
		return mongoTemplate.find(query, this.EntityClass());
	}
	
	
	public List<T> findByList(Query query,PageParam pageParam, String tableName){
		query.skip(pageParam.getFirst());
		query.limit(pageParam.getRows());
		
		String str = pageParam.getOrder().trim().toLowerCase();
		if(str!=null&&str.equals("asc")){
			query.with(new Sort(Direction.ASC,pageParam.getSort()));
		}
		if(str!=null&&str.equals("desc")){
			query.with(new Sort(Direction.DESC,pageParam.getSort()));
		}
		
		return mongoTemplate.find(query, this.EntityClass(),tableName);
	}
	
	public Long totalnum(Query query, String tableName){
		
		return mongoTemplate.count(query, tableName);
	}
	

	public MongoTemplate getMongoTemplate() {
		return mongoTemplate;
	}

	public	boolean save(T t) {
		try {
			mongoTemplate.insert(t);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public boolean save(T t, String tableName) {
		try {
			mongoTemplate.insert(t, tableName);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public	 boolean update(T t){
		Query query = new Query();
		Update update =new Update();
		try {
			anlyvalue(t,update,query);
			mongoTemplate.upsert(query, update, this.EntityClass());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
		 
	 }
	 
	public	 boolean update(T t,String tableName){
		Query query = new Query();
		Update update =new Update();
		try {
			anlyvalue(t,update,query);
			mongoTemplate.upsert(query, update, tableName);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	 }
		
		public Map<String,Object> anlyvalue(T t,Update update,Query query) throws Exception{
			Map<String,Object> map = new HashMap<String,Object>();

			Field[] flds = this.EntityClass().getDeclaredFields();
			for (Field fld : flds) {
				fld.setAccessible(true);
				Object  o=fld.get(t);
				if(o==null){
					continue;
				}
				if (fld.getName().equals("serialVersionUID")|| fld.getName().equals("id")|| fld.getName().equals("_id")){
					if(fld.getName().equals("_id")){
						query.addCriteria(Criteria.where("_id").is(o));
					}
					continue;
				}
				Transient ex = fld.getAnnotation(Transient.class);
				if(ex!=null){
					continue;
				}
				update.set(fld.getName(), o);
			}
			return map;
		}

}
